#include "SQLCreateDatabaseStatement.h"
#include "SQLDDLStatement.h"
#include "SQLAssignItem.h"
#include "../SQLName.h"
#include "../SQLCommentHint.h"
#include "../SQLExpr.h"
#include "../SQLObject.h"
#include "../../../DbType.h"
#include "../../visitor/SQLASTVisitor.h"
#include "../../../utils/listAddAll.h"
#include "../../../utils/instanceof.h"
#include "../expr/SQLPropertyExpr.h"
#include "../../SQLUtils.h"

SQLCreateDatabaseStatement::SQLCreateDatabaseStatement()
{
  hints = std::make_shared<std::list<SQLCommentHint_ptr>>();
  dbProperties = std::make_shared<std::list<SQLAssignItem_ptr>>();
  storedOn = std::make_shared<std::list<SQLAssignItem_ptr>>();
  storedBy = std::make_shared<std::list<SQLAssignItem_list_ptr>>();
}

SQLCreateDatabaseStatement::SQLCreateDatabaseStatement(DbType_ptr  dbType)
    : SQLStatementImpl(dbType)
{
  hints = std::make_shared<std::list<SQLCommentHint_ptr>>();
  dbProperties = std::make_shared<std::list<SQLAssignItem_ptr>>();
  storedOn = std::make_shared<std::list<SQLAssignItem_ptr>>();
  storedBy = std::make_shared<std::list<SQLAssignItem_list_ptr>>();
}

void SQLCreateDatabaseStatement::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLCreateDatabaseStatement)))
  {
    acceptChild(visitor, name);
  }
  visitor->endVisit(SharedObject(SQLCreateDatabaseStatement));
}

SQLObject_list_ptr SQLCreateDatabaseStatement::getChildren()
{
  SQLObject_list_ptr children = std::make_shared<std::list<SQLObject_ptr>>();
  if (name != NULL)
  {
    children->push_back(std::dynamic_pointer_cast<SQLObject>(name));
  }
  return children;
}

SQLName_ptr SQLCreateDatabaseStatement::getName()
{
  return name;
}

void SQLCreateDatabaseStatement::setName(SQLName_ptr name)
{
  this->name = name;
}

string_ptr  SQLCreateDatabaseStatement::getCharacterSet()
{
  return characterSet;
}

void SQLCreateDatabaseStatement::setCharacterSet(string_ptr  characterSet)
{
  this->characterSet = characterSet;
}

string_ptr  SQLCreateDatabaseStatement::getCollate()
{
  return collate;
}

void SQLCreateDatabaseStatement::setCollate(string_ptr  collate)
{
  this->collate = collate;
}

SQLCommentHint_list_ptr SQLCreateDatabaseStatement::getHints()
{
  return hints;
}

void SQLCreateDatabaseStatement::setHints(SQLCommentHint_list_ptr hints)
{
  this->hints->clear(); // = hints;
  Utils::ListAddAll<SQLCommentHint, SQLCommentHint>(hints, this->hints);
}

BOOL_ptr SQLCreateDatabaseStatement::isIfNotExists()
{
  return ifNotExists;
}

void SQLCreateDatabaseStatement::setIfNotExists(BOOL_ptr ifNotExists)
{
  this->ifNotExists = ifNotExists;
}

SQLExpr_ptr SQLCreateDatabaseStatement::getComment()
{
  return comment;
}

string_ptr  SQLCreateDatabaseStatement::getUser()
{
  return user;
}

void SQLCreateDatabaseStatement::setUser(string_ptr  user)
{
  this->user = user;
}

void SQLCreateDatabaseStatement::setComment(SQLExpr_ptr x)
{
  if (x != NULL)
  {
    x->setParent(SharedObject(SQLCreateDatabaseStatement));
  }
  this->comment = x;
}

SQLExpr_ptr SQLCreateDatabaseStatement::getLocation()
{
  return location;
}

std::shared_ptr<std::map<string_ptr , SQLExpr_ptr>> SQLCreateDatabaseStatement::getOptions()
{
  return options;
}

void SQLCreateDatabaseStatement::setLocation(SQLExpr_ptr x)
{
  if (x != NULL)
  {
    x->setParent(SharedObject(SQLCreateDatabaseStatement));
  }
  this->location = x;
}

SQLAssignItem_list_ptr SQLCreateDatabaseStatement::getDbProperties()
{
  return dbProperties;
}

void SQLCreateDatabaseStatement::setOptions(std::shared_ptr<std::map<string_ptr , SQLExpr_ptr>> options)
{
  this->options = options;
}

SQLAssignItem_list_ptr SQLCreateDatabaseStatement::getStoredOn()
{
  return storedOn;
}

std::shared_ptr<std::list<SQLAssignItem_list_ptr>> SQLCreateDatabaseStatement::getStoredBy()
{
  return storedBy;
}

SQLExpr_ptr SQLCreateDatabaseStatement::getStoredAs()
{
  return storedAs;
}

void SQLCreateDatabaseStatement::setStoredAs(SQLExpr_ptr x)
{
  if (x != NULL)
  {
    x->setParent(SharedObject(SQLCreateDatabaseStatement));
  }
  this->storedAs = x;
}

SQLExpr_ptr SQLCreateDatabaseStatement::getStoredIn()
{
  return storedIn;
}

void SQLCreateDatabaseStatement::setStoredIn(SQLExpr_ptr x)
{
  if (x != NULL)
  {
    x->setParent(SharedObject(SQLCreateDatabaseStatement));
  }
  this->storedIn = x;
}

SQLExpr_ptr SQLCreateDatabaseStatement::getPassword()
{
  return password;
}

void SQLCreateDatabaseStatement::setPassword(SQLExpr_ptr x)
{
  if (x != NULL)
  {
    x->setParent(SharedObject(SQLCreateDatabaseStatement));
  }
  this->password = x;
}

string_ptr  SQLCreateDatabaseStatement::getDatabaseName()
{
  if (name == NULL)
  {
    return NULL;
  }

  // if (name instanceof SQLName*) {
  // return ((SQLName*) name).getSimpleName();
  return name->getSimpleName();
  // }

  return NULL;
}

void SQLCreateDatabaseStatement::setDatabase(string_ptr  database)
{
  SQLExpr_ptr expr = SQLUtils::toSQLExpr(database);

  if (instanceof <SQLExpr, SQLIdentifierExpr>(expr) && instanceof <SQLName, SQLPropertyExpr>(name))
  {
    std::dynamic_pointer_cast<SQLPropertyExpr>(this->name)->setName((database));
    return;
  }

  expr->setParent(SharedObject(SQLCreateDatabaseStatement));
  this->name = std::dynamic_pointer_cast<SQLName>(expr);
}

string_ptr  SQLCreateDatabaseStatement::getServer()
{
  if (instanceof <SQLName, SQLPropertyExpr>(name))
  {
    SQLExpr_ptr owner = std::dynamic_pointer_cast<SQLPropertyExpr>(name)->getOwner();
    if (instanceof <SQLExpr, SQLIdentifierExpr>(owner))
    {
      return (std::dynamic_pointer_cast<SQLIdentifierExpr>(owner)->getName());
    }

    if (instanceof <SQLExpr, SQLPropertyExpr>(owner))
    {
      return (std::dynamic_pointer_cast<SQLPropertyExpr>(owner)->getName());
    }
  }

  return NULL;
}

BOOL_ptr SQLCreateDatabaseStatement::setServer(string_ptr  server)
{
  if (name == NULL)
  {
    return BOOL::FALSE;
  }

  if (instanceof <SQLName, SQLIdentifierExpr>(name))
  {
    SQLPropertyExpr_ptr propertyExpr = SQLPropertyExpr_ptr(
        new SQLPropertyExpr(
            SQLIdentifierExpr_ptr(new SQLIdentifierExpr((server))),
            (std::dynamic_pointer_cast<SQLIdentifierExpr>(name)->getName())));
    propertyExpr->setParent(SharedObject(SQLCreateDatabaseStatement));
    name = propertyExpr;
    return BOOL::TRUE;
  }

  if (instanceof <SQLName, SQLPropertyExpr>(name))
  {
    SQLPropertyExpr_ptr propertyExpr = std::dynamic_pointer_cast<SQLPropertyExpr>(name);
    SQLExpr_ptr owner = propertyExpr->getOwner();
    if (instanceof <SQLExpr, SQLIdentifierExpr>(owner))
    {
      propertyExpr->setOwner(SQLIdentifierExpr_ptr(new SQLIdentifierExpr((server))));
      return BOOL::TRUE;
    }
    else if (instanceof <SQLExpr, SQLPropertyExpr>(owner))
    {
      std::dynamic_pointer_cast<SQLPropertyExpr>(owner)->setName((server));
      return BOOL::TRUE;
    }
  }

  return BOOL::FALSE;
}

BOOL_ptr SQLCreateDatabaseStatement::isPhysical()
{
  return physical;
}

void SQLCreateDatabaseStatement::setPhysical(BOOL_ptr physical)
{
  this->physical = physical;
}

SQLDDLStatement::DDLObjectType SQLCreateDatabaseStatement::getDDLObjectType()
{
  return SQLDDLStatement::DDLObjectType::DATABASE;
}
